package com.huilian.iotbox.mqtt.server.base.handler;

import com.huilian.iotbox.data.cmd.PositiveDataFrameCMD;
import com.huilian.iotbox.data.enums.DeviceOnlineOfflineRecordEnum;
import com.huilian.iotbox.data.po.DeviceItem;
import com.huilian.iotbox.data.service.DeviceCommonService;
import com.huilian.iotbox.data.vo.DeviceItemVo;
import com.huilian.iotbox.mqtt.server.base.producer.RabbitProducer;
import com.huilian.iotbox.mqtt.server.base.service.DeviceItemService;
import com.huilian.iotbox.mqtt.server.base.service.DeviceService;
import com.huilian.iotbox.mqtt.server.base.service.ProductService;
import com.huilian.iotbox.aliyun.service.PubService;
import com.huilian.iotbox.data.cmd.RespondDataFrameCMD;
import com.huilian.iotbox.data.common.RedisKey;
import com.huilian.iotbox.data.dto.DeviceDto;
import com.huilian.iotbox.data.enums.AgreementVersionEnum;
import com.huilian.iotbox.data.enums.DeviceStatusEnum;
import com.huilian.iotbox.data.po.Product;
import com.huilian.iotbox.data.utils.IotBoxUtil;
import com.huilian.iotbox.data.vo.DeviceVo;
import com.huilian.iotbox.mqtt.server.base.service.RabbitSenderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * HeartbeatHandler
 * 心跳处理
 *
 * @Author mineChen
 * @Date 2021/8/26 下午 05:39
 */
@Service("messageHandleService01")
@Slf4j
public class HeartbeatHandler implements MessageHandlerStrategy {
    @Value("${huilian.iot.apiProductKey}")
    private String apiProductKey;
    @Autowired
    private PubService pubService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private RabbitProducer rabbitProducer;
    @Autowired
    private ProductService productService;
    @Autowired
    private RabbitSenderService rabbitSenderService;
    @Autowired
    private DeviceCommonService deviceCommonService;
    @Autowired
    private RedisTemplate<String, Serializable> redisCacheTemplate;
    @Autowired
    private DeviceItemService deviceItemService;

    @Override
    public void process(String content, String deviceNo, String productKey, Integer serviceProviderCode) {

        /**
         * 嘉德宝-兑币机
         * AA1301011ECC1100000000000000000000000000D0DD
         *
         *
         */

        final String networkStr = content.substring(8, 10);
        final int network = IotBoxUtil.singleHex2Int(networkStr);
        log.info("{}盒子信号: {}", deviceNo, network);

        // 更新盒子设备状态
        DeviceVo deviceVo = deviceService.findOneDeviceByDeviceNo(deviceNo);

        // API盒子需要发给中间件
        if (deviceVo.getIsApi()) {
            pubService.pub(content, deviceNo, apiProductKey);
        }

        Boolean loginState = true;

        // 找不到该设备
        if (StringUtils.isEmpty(deviceVo) || DeviceStatusEnum.OFF_LINE.getCode().equals(deviceVo.getStatus())) {
            loginState = false;
            log.warn("找不到该设备: {}", deviceNo);
            String heart = RespondDataFrameCMD.heart(loginState);
            pubService.pub(heart, deviceNo, productKey);
            return;
        }
        String heart = RespondDataFrameCMD.heart(loginState);
        pubService.pub(heart, deviceNo, productKey);

        if (deviceVo.getNetworkIntensity().compareTo(0) == 0) {
            // 记录上线时间
            deviceVo.setStartDate(new Date());
            deviceVo.setDeviceOnlineOfflineRecordType(DeviceOnlineOfflineRecordEnum.ONLINE.getCode());
            rabbitSenderService.deviceOnlineOrOffline(deviceVo);
        }

        // 处理登录标识，没连上就是0
        final String loginCodeHex = content.substring(10, 16);
        String loginCode = IotBoxUtil.hexHighToLow(loginCodeHex);
        final Integer loginId = IotBoxUtil.singleHex2Int(loginCode);
        log.info(deviceNo + "登录标识是：" + loginId);
        Product product = null;
        if (!StringUtils.isEmpty(loginId) && loginId.compareTo(0) == 1) {
            product = productService.findOneProductByLoginId(loginId);
        }

        Integer productId = -1;
        DeviceDto deviceDto = new DeviceDto();

        if (!StringUtils.isEmpty(product)) {
            productId = product.getId();
            deviceDto.setDeviceTypeId(product.getDeviceTypeId());
        }

        Integer serviceProvider = deviceCommonService.getServiceProvider(deviceNo);
        if (!serviceProviderCode.equals(serviceProvider)) {
            // 缓存拿到的跟数据库不一致时就要立马更新
            redisCacheTemplate.delete(String.format(RedisKey.DEVICE_SERVICE_PROVIDER, deviceNo));
            serviceProvider = serviceProviderCode;
            deviceDto.setServiceProvider(serviceProviderCode);
        }

        deviceDto.setId(deviceVo.getId());
        deviceDto.setNetworkIntensity(network);
        deviceDto.setLastHeartbeat(new Date());
        DeviceItem deviceItem = new DeviceItem();
        deviceItem.setDeviceId(deviceVo.getId());
        deviceItem.setPositionId(-1);
        Integer agreementVersion = (Integer) redisCacheTemplate.opsForValue().get(String.format(RedisKey.AGREEMENT_VERSION_OLD, deviceVo.getId()));
        // 判断当前设备协议新旧
        if (!StringUtils.isEmpty(agreementVersion)) {
            // 旧协议的时候
            deviceDto.setProductId(null);
            deviceItem.setProductId(null);
        } else {
            deviceDto.setProductId(productId);
            deviceItem.setProductId(productId);
            deviceDto.setAgreementVersion(AgreementVersionEnum.NEW.getCode());
        }

        if (!StringUtils.isEmpty(loginId) && loginId > 0) {
            deviceDto.setLoginId(loginId);
            deviceItem.setLoginId(loginId);
            DeviceItem di =  deviceItemService.getDeviceItem(deviceItem);
            if(StringUtils.isEmpty(di)){
                deviceItemService.add(deviceItem);
            }else{
                deviceItem.setId(di.getId());
                deviceItemService.update(deviceItem);
            }
        }
        deviceService.updateDeviceById(deviceDto);
    }
}
